package view;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Polygon;
import map.Map;
import map.Tile;

/**
 * The view class displays Map objects in areas on the screen.
 * 
 * @author Kyle_Solo
 */
public class View {
	/**
	 * Used in calculating mouse position and drawing the hex grid.
	 */
	private Polygon hex;
	/**
	 * map is the map that this view will display
	 */
	private Map map;
	/**
	 * A quarter of the width of a tile, used in the drawing functions.
	 */
	private int qx;
	/**
	 * A quarter of the height of a tile, used in the drawing functions.
	 */
	private int qy;
	/**
	 * The height of a tile in pixels.
	 */
	private int tileHeight;
	/**
	 * The width of a tile in pixels.
	 */
	private int tileWidth;
	/**
	 * tileX, tileY is the tile that will be drawn in the center of the view
	 */
	private int tileX = 2;
	/**
	 * tileX, tileY is the tile that will be drawn in the center of the view
	 */
	private int tileY = 2;
	/**
	 * The height of the view in pixels
	 */
	private int viewHeight;
	/**
	 * The width of the view in pixels
	 */
	private int viewWidth;
	/**
	 * viewX, viewY is the location in pixels where the view will be drawn on a graphics context
	 */
	private int viewX;
	/**
	 * viewX, viewY is the location in pixels where the view will be drawn on a graphics context
	 */
	private int viewY;

	/**
	 * Constructs a new view
	 * 
	 * @param map
	 * @param x
	 * @param y
	 * @param viewWidth
	 * @param viewHeight
	 * @param tileWidth
	 * @param tileHeight
	 */
	public View(Map map, int x, int y, int viewWidth, int viewHeight, int tileWidth, int tileHeight) {
		viewX = x;
		viewY = y;
		this.viewWidth = viewWidth;
		this.viewHeight = viewHeight;
		this.tileWidth = tileWidth;
		this.tileHeight = tileHeight;
		this.map = map;
		updateHexagon();
	}

	/**
	 * @return the tileHeight
	 */
	public int getTileHeight() {
		return tileHeight;
	}

	/**
	 * @return the tileWidth
	 */
	public int getTileWidth() {
		return tileWidth;
	}

	/**
	 * @return the viewHeight
	 */
	public int getViewHeight() {
		return viewHeight;
	}

	/**
	 * @return the viewWidth
	 */
	public int getViewWidth() {
		return viewWidth;
	}

	/**
	 * @return the viewX
	 */
	public int getX() {
		return viewX;
	}

	/**
	 * @return the viewY
	 */
	public int getY() {
		return viewY;
	}

	/**
	 * Draws this view onto the graphics context. The view will occupy a rectangle (viewX, viewY,
	 * viewWidth, viewHeight).
	 * 
	 * @param g2d
	 *            the graphics context to draw the view upon
	 * @param mouseX
	 *            the x coordinate of the mouse on the screen
	 * @param mouseY
	 *            the y coordinate of the mouse on the screen
	 */
	public void render(Graphics2D g2d, int mouseX, int mouseY) {
		// create a new graphics context so we don't pollute the original
		Graphics2D graphics = (Graphics2D) g2d.create();
		graphics.setClip(viewX, viewY, viewWidth, viewHeight);
		graphics.setColor(Color.black);
		graphics.translate(viewX, viewY);
		graphics.fillRect(0, 0, viewWidth - 1, viewHeight - 1);
		graphics.translate(viewWidth / 2, viewHeight / 2);
		int hTiles = viewWidth / (qx * 3);
		int vTiles = viewHeight / (qy * 2);

		for (int y = -vTiles / 2 - 1; y <= vTiles / 2 + 1; y++) {
			for (int x = -hTiles / 2 - 1; x <= hTiles / 2 + 1; x++) {
				int tx = x + tileX;
				int ty = y + tileY;
				if (map.contains(tx, ty)) {
					Tile t = map.getTile(tx, ty);
					if (t != null) {
						graphics.setColor(Color.green);
						/*
						 * These statements ensure that the center tile is always drawn in the
						 * center, and handle the differences in tile position based on whether y is
						 * even or odd.
						 */
						if (tileY % 2 == 0) {
							if (ty % 2 == 0) {
								t.render(graphics, x * qx * 6, y * qy * 2);
							} else {
								t.render(graphics, 3 * qx + x * qx * 6, y * qy * 2);
							}
						} else {
							if (ty % 2 == 0) {
								t.render(graphics, x * qx * 6 - 3 * qx, y * qy * 2);
							} else {
								t.render(graphics, x * qx * 6, y * qy * 2);
							}
						}
					}
				}

			}

		}
		graphics.dispose();
	}

	/**
	 * @param tileHeight
	 *            the tileHeight to set
	 */
	public void setTileHeight(int tileHeight) {
		this.tileHeight = tileHeight;
	}

	/**
	 * @param tileWidth
	 *            the tileWidth to set
	 */
	public void setTileWidth(int tileWidth) {
		this.tileWidth = tileWidth;
		updateHexagon();
	}

	/**
	 * @param viewHeight
	 *            the viewHeight to set
	 */
	public void setViewHeight(int viewHeight) {
		this.viewHeight = viewHeight;
		updateHexagon();
	}

	/**
	 * @param viewWidth
	 *            the viewWidth to set
	 */
	public void setViewWidth(int viewWidth) {
		this.viewWidth = viewWidth;
	}

	/**
	 * @param viewX
	 *            the viewX to set
	 */
	public void setX(int viewX) {
		this.viewX = viewX;
	}

	/**
	 * @param viewY
	 *            the viewY to set
	 */
	public void setY(int viewY) {
		this.viewY = viewY;
	}

	/**
	 * This method defines the size/shape of the hexagonal tiles. The hexagon generated here is used
	 * in detected which tile the mouse is on, if any, and used in drawing the grid if that option
	 * is enabled.
	 */
	private void updateHexagon() {
		qx = tileWidth / 4;
		qy = tileWidth / 4;
		hex = new Polygon();
		hex.addPoint(-2 * qx, 0);
		hex.addPoint(-qx, -2 * qy);
		hex.addPoint(qx, -2 * qy);
		hex.addPoint(2 * qx, 0);
		hex.addPoint(qx, 2 * qy);
		hex.addPoint(-qx, 2 * qy);
	}

	/**
	 * Centers the view on a tile
	 * 
	 * @param t
	 *            the tile to center upon
	 */
	public void viewCenter(Tile t) {
		tileX = t.x;
		tileY = t.y;
	}
}
